#include <map>
#include "AudioEncode.h"
#include "mediaPriv.h"
#include "Thread/Thread.h"
#include "frame_common.h"

using namespace Fdt;

namespace Media{
std::map<int, AudioEncode *> AudioEncode::s_encoder_map;

AudioEncode *AudioEncode::instance(int channel){
	if(s_encoder_map.find(channel) == s_encoder_map.end()){
		s_encoder_map[channel] = new AudioEncode(channel);
	}

	return s_encoder_map[channel];
}

AudioEncode::AudioEncode(int channel) : _channel(channel){

    createEncoder();

	//Init();

	memset(&_encpPacket, 0, sizeof(_encpPacket));
	//_encpPacket.buffer = (uchar *)malloc(MAX_PCM_SIZE*sizeof(uchar));
}

bool AudioEncode::createEncoder()
{
    int status = 0;
    AudioEncDesc encDesc = {0};    
    
	encDesc.channel = _channel;
    status = createAudioEncoder(&encDesc, &_audioEncoder);
    if (status)
    {
        errorf("createAudioEncoder failed\n");
        return false;
    }

    return true;
}

bool AudioEncode::Init(){
	
    memset(&_encFormat, 0, sizeof(AudioEncFormat));

    _encFormat.type = audioEncPCM; //audioEncAAC
    _encFormat.pack = audioEncPackTypeADTS;
    _encFormat.frequency = 48000;
    _encFormat.channelNum = 2;
    _encFormat.depth = 16;

    return setFormat(&_encFormat);
}

bool AudioEncode::setFormat(AudioEncFormat *format){
#if 1
	std::lock_guard<std::recursive_mutex> guard(_mutex);
	if(_started){
		stop();
	}

	if(!_audioEncoder || _audioEncoder->setFormat(_audioEncoder, format) < 0){
	    return false;
	}

	memcpy(&_encFormat, format, sizeof(AudioEncFormat));
	
	if(_started){
		start();
	}

#endif
    return true;
}

bool AudioEncode::getFormat(AudioEncFormat *format){
	if(!format)
		return false;
	memcpy(format, &_encFormat, sizeof(AudioEncFormat));
	return true;
}


bool AudioEncode::start(void *thiz, const FrameCommon::frame_callback_func &callback){
	std::lock_guard<std::recursive_mutex> guard(_mutex);
	if(_func_map.find(thiz) != _func_map.end())
	{
		return true;
	}
	_func_map[thiz] = std::make_shared<FrameCommon::frame_callback_func>(callback);
	if(!_started){
		_started =  start();
	}
	return _started;
}

bool AudioEncode::stop(void *thiz)
{
	std::lock_guard<std::recursive_mutex> guard(_mutex);

	if(_func_map.find(thiz) == _func_map.end()){
		return false;
	}
	_func_map.erase(thiz);
	if(_func_map.empty() && _started){
		_started = !stop();
		return !_started;
	}

	return true;
}


bool AudioEncode::start(){

    if(!_audioEncoder || _audioEncoder->start(_audioEncoder) < 0)
    {
        return false;
    }

	if(_channel == RTSP_MAIN_OUT) //暂时只处理RTSP_MAIN_OUT的rtsp输出
	{
	    _thread.start([this](Fdt::Thread *thread){this->ThreadProc(thread);});
	}
	return true;
}

bool AudioEncode::stop(){
    if(_channel == RTSP_MAIN_OUT)
    {
	    _thread.stop();
	}
	
	if(!_audioEncoder || _audioEncoder->stop(_audioEncoder) < 0)
    {
        return false;
    }
	return true;
}


bool AudioEncode::getPacket(char *buffer, int* length)
{
    if(!_audioEncoder)
	{
        errorf("AudioEncode _audioEncoder is NULL\n");
        return false;
	}

    _encpPacket.buffer = buffer;

    int ret = _audioEncoder->getPacket(_audioEncoder, &_encpPacket);
    if(ret)
    {
        //errorf("AudioEncode getPacket failed");
        return false;
    }

    *length = _encpPacket.length;

    return true;
}



bool AudioEncode::getPacket(char *buffer, int* length, uint64& pts)
{
    if(!_audioEncoder)
	{
        errorf("AudioEncode _audioEncoder is NULL\n");
        return false;
	}

    _encpPacket.buffer = buffer;

    int ret = _audioEncoder->getPacket(_audioEncoder, &_encpPacket);
    if(ret)
    {
        //errorf("AudioEncode getPacket failed");
        return false;
    }

    *length = _encpPacket.length;
	pts = _encpPacket.pts;
    return true;
}


bool AudioEncode::getSpecificInfo(char **ppBuffer, unsigned long *pSize)
{
    if(!_audioEncoder || _audioEncoder->getSpecificInfo(_audioEncoder, ppBuffer, pSize) < 0)
    {
        return false;
    }
    
    return true;
}


#if 1
#define AUDIO_FRAME_SIZE        4096

void AudioEncode::ThreadProc(Fdt::Thread *thread)
{
	tracef("AudioEncode Thread tid %d", thread->tid());
    thread->setPriority(Fdt::PRIORITY_NORMAL, Fdt::POLICY_RR);
    char buf[1024];

    _start_time = 0;
    while (thread->running())
    {
    	char audioBuf[AUDIO_FRAME_SIZE] = {0};
        int audioLen = 0;

        memset(audioBuf, 0, sizeof(audioBuf));

        while(getPacket(audioBuf, &audioLen)){
            char *   ptr    = audioBuf;
        	size_t   size   = audioLen;
        	char *   pext   = nullptr;
        	size_t   exsize = 0;
        	if(_start_time == 0){
        		_start_time = getCurrentMillisecond();
        		_start_time = _start_time *48;
        		_pts = _start_time;
        	}
        	else{
        		_pts += 1024;
        	}

        	uint64_t pts = getCurrentMillisecond();

        	//FrameFromPtr::Ptr framePtr = FrameFromPtr::create(CodecAAC, ptr, size, _pts, _pts, 7, false, _pts);
			auto framePtr = FrameCommon::Frame::CreateFrame(FrameCommon::AAC, ptr, 
			size, pts, pts, false, _pts, 7);

        	_mutex.lock();
        	auto func_map = _func_map;
        	_mutex.unlock();

        	for(auto &func : func_map){
        		(*(func.second))(framePtr);
        	}
        }
        thread->sleep(8);
    }
    _start_time = 0;
}
#endif

}//namespace Media
